package com.example.hello.controller;

import com.example.hello.common.Result;
import com.example.hello.dto.LoginDTO;
import com.example.hello.dto.RegisterDTO;
import com.example.hello.dto.UserDTO;
import com.example.hello.dto.ForgotPasswordDTO;
import com.example.hello.dto.ResetPasswordDTO;
import com.example.hello.entity.User;
import com.example.hello.security.JwtTokenUtil;
import com.example.hello.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Tag(name = "认证管理", description = "用户登录认证相关接口")
@RestController
@RequestMapping("/api/auth")
public class AuthController {

  private static final Logger logger = LogManager.getLogger(AuthController.class);

  @Autowired
  private UserService userService;

  @Autowired
  private PasswordEncoder passwordEncoder;

  @Autowired
  private JwtTokenUtil jwtTokenUtil;

  @Autowired
  private AuthenticationManager authenticationManager;

  @Operation(summary = "用户登录", description = "用户登录并获取认证令牌")
  @ApiResponses(value = {
      @ApiResponse(responseCode = "200", description = "登录成功"),
      @ApiResponse(responseCode = "401", description = "用户名或密码错误")
  })
  @PostMapping("/login")
  public Result<Map<String, Object>> login(@RequestBody @Validated LoginDTO loginDTO) {
    logger.info("用户登录: {}", loginDTO.getUsername());
    try {
      // 验证用户名和密码
      Authentication authentication = authenticationManager.authenticate(
          new UsernamePasswordAuthenticationToken(loginDTO.getUsername(), loginDTO.getPassword()));

      // 生成JWT令牌
      UserDetails userDetails = (UserDetails) authentication.getPrincipal();
      String token = jwtTokenUtil.generateToken(userDetails);

      // 更新用户最后登录时间
      User user = userService.getUserByUsername(loginDTO.getUsername());
      user.setLastLogin(new Date());
      userService.updateUserInfo(convertToUserDTO(user));

      // 返回令牌和用户信息
      Map<String, Object> data = new HashMap<>();
      data.put("token", token);
      data.put("user", user);

      logger.info("用户 {} 登录成功", loginDTO.getUsername());
      return Result.success(data);
    } catch (BadCredentialsException e) {
      logger.warn("用户 {} 登录失败: 用户名或密码错误", loginDTO.getUsername());
      return Result.error(401, "用户名或密码错误");
    }
  }

  @Operation(summary = "用户注册", description = "注册新用户，只需填写用户名、密码、邮箱和手机号，昵称默认与用户名一致")
  @ApiResponses(value = {
      @ApiResponse(responseCode = "200", description = "注册成功"),
      @ApiResponse(responseCode = "400", description = "注册失败，请求参数错误"),
      @ApiResponse(responseCode = "409", description = "注册失败，用户名/邮箱/手机号已存在")
  })
  @PostMapping("/register")
  public Result<User> register(@RequestBody @Validated RegisterDTO registerDTO) {
    logger.info("新用户注册: {}", registerDTO.getUsername());
    try {
      User user = userService.register(registerDTO);
      logger.info("用户 {} 注册成功", registerDTO.getUsername());
      return Result.success(user);
    } catch (Exception e) {
      logger.error("用户 {} 注册失败: {}", registerDTO.getUsername(), e.getMessage(), e);
      return Result.error(500, "注册失败：" + e.getMessage());
    }
  }

  @Operation(summary = "忘记密码", description = "验证邮箱和手机号，生成验证码")
  @ApiResponses(value = {
      @ApiResponse(responseCode = "200", description = "验证成功，返回验证码"),
      @ApiResponse(responseCode = "400", description = "验证失败，邮箱或手机号不匹配")
  })
  // @PostMapping("/forgot-password")
  public Result<String> forgotPassword(@RequestBody @Validated ForgotPasswordDTO forgotPasswordDTO) {
    logger.info("忘记密码请求: {}", forgotPasswordDTO.getEmail());
    try {
      String verificationCode = userService.forgotPassword(forgotPasswordDTO);
      // 在实际应用中，不应该直接返回验证码，而是通过邮件发送
      // 这里为了演示方便，直接返回验证码
      return Result.success(verificationCode);
    } catch (RuntimeException e) {
      logger.error("忘记密码处理失败: {}", e.getMessage(), e);
      return Result.error(400, e.getMessage());
    }
  }

  @Operation(summary = "重置密码", description = "重置用户密码")
  @ApiResponses(value = {
      @ApiResponse(responseCode = "200", description = "密码重置成功"),
      @ApiResponse(responseCode = "400", description = "请求参数错误")
  })
  // @PostMapping("/reset-password")
  public Result<Void> resetPassword(
      @RequestBody @Validated ResetPasswordDTO resetPasswordDTO) {
    
    // 验证两次密码是否一致
    if (!resetPasswordDTO.getNewPassword().equals(resetPasswordDTO.getConfirmPassword())) {
        return Result.error(400, "两次输入的密码不一致");
    }
    
    // 从当前认证信息中获取用户名
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    String username = authentication.getName();
    
    // 重置密码
    boolean success = userService.resetPassword(username, resetPasswordDTO.getNewPassword());
    
    if (success) {
        return Result.success();
    } else {
        return Result.error(500, "密码重置失败");
    }
  }

  private UserDTO convertToUserDTO(User user) {
    UserDTO userDTO = new UserDTO();
    userDTO.setUserId(user.getUserId());
    userDTO.setUsername(user.getUsername());
    userDTO.setEmail(user.getEmail());
    userDTO.setPhone(user.getPhone());
    userDTO.setAvatar(user.getAvatar());
    userDTO.setGender(user.getGender());
    userDTO.setNickname(user.getNickname());
    userDTO.setBirthday(user.getBirthday());
    userDTO.setLocation(user.getLocation());
    return userDTO;
  }
}